﻿using System.Collections.Generic;
using System.Linq;
using System.Web.Mvc;
using System.Web.Security;
using Dexter.Domain.Results;
using Dexter.Logger.Contracts;
using Dexter.Services;
using Dexter.Web.Mvc.Extensions;
using Dexter.Web.Mvc.Filters;
using Dexter.Web.Mvc.ViewModel.Backoffice.Binders;
using Dexter.Web.Mvc.ViewModel.Backoffice.ViewsData.AccountController;
using Dexter.Web.Utils;

namespace Dexter.Web.Mvc.Controllers.Backoffice {
	[Authorize(Roles="Administrator")]
	[DexterCallFilter ( false )]
	public class AccountController : BackOfficeControllerBase {

		/// <summary>
		/// Initializes a new instance of the <see cref="AccountController"/> class.
		/// </summary>
		/// <param name="configurationService">The configuration service.</param>
		/// <param name="webUtils">The web utils.</param>
		/// <param name="logger">The logger.</param>
		/// <param name="urlBuilder">The URL builder.</param>
		/// <param name="contactService">The contact service.</param>
		public AccountController ( IConfigurationService configurationService , IWebUtils webUtils , ILogger logger , IUrlBuilder urlBuilder , IContactService contactService ) : base ( configurationService , webUtils , logger , urlBuilder , contactService ) {}

		[AcceptVerbs ( HttpVerbs.Get )]
		public ActionResult Index ( int? page ) {
			int pageIndex = page ?? 1;

			pageIndex--;

			int totalrecords;
			MembershipUserCollection usrs = Membership.GetAllUsers ( pageIndex , 50 , out totalrecords );

			IList <MembershipUser> users = usrs.Cast <MembershipUser> ( ).ToList ( );

			var data = base.GetViewData ( new AccountIndexViewData ( base.WebUtils , base.Configuration , base.UrlBuilder ) );
			data.Users = new PagedResult <MembershipUser> ( pageIndex , 50 , users , totalrecords );

			return View ( data );
		}

		[AcceptVerbs ( HttpVerbs.Get )]
		public ActionResult ChangePassword ( string id ) {
			var data = base.GetViewData ( new AccountChangePasswordViewData ( base.WebUtils , base.Configuration , base.UrlBuilder ) );
			data.UserPasswordBinder = new PasswordBinder {Username = id};

			return View ( data );
		}

		[ValidateAntiForgeryToken]
		[AcceptVerbs ( HttpVerbs.Post )]
		public ActionResult ChangePassword ( PasswordBinder userPasswordBinder ) {
			if (!ModelState.IsValid) {
				var data = base.GetViewData ( new AccountChangePasswordViewData ( base.WebUtils , base.Configuration , base.UrlBuilder ) );
				data.UserPasswordBinder = new PasswordBinder {Username = userPasswordBinder.Username};

				return View ( data );
			}

			MembershipUser mu = Membership.GetUser ( userPasswordBinder.Username );
			bool res = mu == null ? false : mu.ChangePassword ( userPasswordBinder.OldPassword, userPasswordBinder.NewPassword );

			if (!res)
				return this.ReturnFeedback ( MessageType.Negative, "UserPasswordChangeFailed", true );

			return this.ReturnFeedback ( MessageType.Positive, "UserPasswordChanged", base.UrlBuilder.BackOffice.UserList );
		}

		[AcceptVerbs ( HttpVerbs.Post )]
		public ActionResult UserUnLock ( string id ) {
			if(string.IsNullOrEmpty ( id ))
				return RedirectToAction ( "Negative", "Message", new {
					Area = "Admin",
					id = "UserNotFound"
				} );

			MembershipUser mu = Membership.GetUser ( id );

			if (mu == null)
				return RedirectToAction ( "Negative", "Message", new {
					Area = "Admin",
					id = "UserNotFound"
				} );

			mu.UnlockUser ( );

			return RedirectToAction ( "Positive", "Message", new {
				Area = "Admin",
				id = "UserUnlocked"
			} );
		}

		[AcceptVerbs ( HttpVerbs.Get )]
		public ActionResult ChangePermissions ( string id ) {
			if(string.IsNullOrEmpty ( id ))
				return this.ReturnFeedback ( MessageType.Negative, "UserNotFound", base.UrlBuilder.BackOffice.UserList );

			var user = Membership.GetUser ( id );

			if (user == null)
				return this.ReturnFeedback ( MessageType.Negative, "UserNotFound", base.UrlBuilder.BackOffice.UserList );

			string[] roles = Roles.GetRolesForUser ( id );

			var data = new ChangePermissionViewData ( base.WebUtils , base.Configuration , base.UrlBuilder ) {
				Roles = new ChangePermissionBinder {
					IsAdministrator = roles.Where ( x => x.ToLowerInvariant ( ) == "administrator" ).Any ( ) ? true : false,
					IsModerator = roles.Where ( x => x.ToLowerInvariant ( ) == "moderator" ).Any ( ) ? true : false,
					IsPoster = roles.Where ( x => x.ToLowerInvariant ( ) == "poster" ).Any ( ) ? true : false,
				}
			};

			return View ( data );
		}

		[ValidateAntiForgeryToken]
		[AcceptVerbs ( HttpVerbs.Post )]
		public ActionResult ChangePermissions (  string id, ChangePermissionBinder roles ) {
			if (roles == null)
				return this.ReturnFeedback ( MessageType.Negative, "UserNotFound", base.UrlBuilder.BackOffice.UserList );

			if (string.IsNullOrEmpty ( id ))
				return this.ReturnFeedback ( MessageType.Negative, "UserNotFound", base.UrlBuilder.BackOffice.UserList );

			if (!ModelState.IsValid) {
				var data = base.GetViewData ( new ChangePermissionViewData ( base.WebUtils , base.Configuration , base.UrlBuilder ) );
				data.Roles = roles;

				return View ( data );
			}

			if(roles.IsAdministrator)
				Roles.AddUserToRole ( id, "Administrator" );
			else {
				Roles.RemoveUserFromRole ( id, "Administrator" );
			}

			if(roles.IsModerator)
				Roles.AddUserToRole ( id, "Moderator" );
			else {
				Roles.RemoveUserFromRole ( id, "Moderator" );
			}

			if(roles.IsPoster)
				Roles.AddUserToRole ( id, "Poster" );
			else {
				Roles.RemoveUserFromRole ( id, "Poster" );
			}

			return this.ReturnFeedback ( MessageType.Positive , "UserRoleChanged" , base.UrlBuilder.BackOffice.UserList );
		}

		[AcceptVerbs ( HttpVerbs.Get )]
		public ActionResult CreateUser ( string id ) {
			var data = base.GetViewData ( new AccountCreateUserViewData ( base.WebUtils, base.Configuration, base.UrlBuilder ) );
			data.User = UserBinder.EmptyInstance ( );

			return View ( data );
		}

		[ValidateAntiForgeryToken]
		[AcceptVerbs ( HttpVerbs.Post )]
		public ActionResult CreateUser ( UserBinder user ) {
			if (!ModelState.IsValid) {
				var data = base.GetViewData ( new AccountCreateUserViewData ( base.WebUtils, base.Configuration, base.UrlBuilder ) );
				data.User = user;

				return View ( data );
			}

			MembershipCreateStatus status;

			Membership.CreateUser ( user.Username, user.Password, user.Email, null, null, true, null, out status );

			if (status == MembershipCreateStatus.DuplicateEmail) {
				ModelState.AddModelError ( "DuplicatedUserName" ,"The specified email is used by another user!");

				var data = base.GetViewData ( new AccountCreateUserViewData ( base.WebUtils, base.Configuration, base.UrlBuilder ) );
				data.User = user;

				return View ( data );
			}

			if (status == MembershipCreateStatus.DuplicateUserName) {
				ModelState.AddModelError ( "DuplicateUserName", "The specified username is used by another user!" );

				var data = base.GetViewData ( new AccountCreateUserViewData ( base.WebUtils, base.Configuration, base.UrlBuilder ) );
				data.User = user;

				return View ( data );
			}

			if (status == MembershipCreateStatus.UserRejected) {
				ModelState.AddModelError ( "UserRejected", "The specified username is used by another user!" );

				var data = base.GetViewData ( new AccountCreateUserViewData ( base.WebUtils, base.Configuration, base.UrlBuilder ) );
				data.User = user;

				return View ( data );
			}

			if(user.IsAdministrator)
				Roles.AddUserToRole ( user.Username, "Administrator" );

			if (user.IsModerator)
				Roles.AddUserToRole ( user.Username, "Moderator" );

			if (user.IsPoster)
				Roles.AddUserToRole ( user.Username, "Poster" );

			return this.ReturnFeedback ( MessageType.Positive, "UserSaved", base.UrlBuilder.BackOffice.UserList );
		}

		[AcceptVerbs ( HttpVerbs.Get )]
		public ActionResult ConfirmDelete ( string id ) {
			if (string.IsNullOrEmpty ( id ))
				return HttpNotFound ( );

			var data = base.GetViewData ( new AccountDeleteViewData ( base.WebUtils, base.Configuration, base.UrlBuilder ) );
			data.User = Membership.GetUser ( id );

			return View ( data );
		}

		[AcceptVerbs ( HttpVerbs.Post )]
		[ValidateAntiForgeryToken]
		public ActionResult Delete ( string id ) {
			bool deleted = Membership.DeleteUser ( id );

			return !deleted
			       	? this.ReturnFeedback ( MessageType.Negative, "UserNotFound", true )
					: this.ReturnFeedback ( MessageType.Positive, "UserDeleted" );
		}
	}
}